package edu.cmu.cs.stage3.alice.authoringtool.dialog;

import edu.cmu.cs.stage3.resourceBundle.I18n;

import javax.swing.ScrollPaneConstants;

import edu.cmu.cs.stage3.alice.authoringtool.AuthoringTool;
import edu.cmu.cs.stage3.swing.ContentPane;

public class RenderContentPane extends ContentPane {

 private static final int HEIGHT = 500; // initial height to the outputs

 protected javax.swing.JPanel renderPanel = new javax.swing.JPanel( new java.awt.BorderLayout() );
 protected javax.swing.JPanel buttonPanel = new javax.swing.JPanel( new java.awt.GridBagLayout() );
 protected javax.swing.JSplitPane stdOutSplitPane = new javax.swing.JSplitPane( javax.swing.JSplitPane.VERTICAL_SPLIT );
 protected double aspectRatio;
 protected AuthoringTool authoringTool;
 protected boolean showStdOut = false;
 protected int stdOutHeight = 200; // 100;
 protected int watcherWidth = 200;
 protected OutputComponent stdOutOutputComponent;
 protected edu.cmu.cs.stage3.alice.authoringtool.util.WatcherPanel watcherPanel;
 protected javax.swing.JScrollPane watcherScrollPane;
 protected javax.swing.JSplitPane watcherSplitPane = new javax.swing.JSplitPane( javax.swing.JSplitPane.HORIZONTAL_SPLIT );
 protected javax.swing.JButton pauseButton;
 protected javax.swing.JButton resumeButton;
 protected javax.swing.JButton restartButton;
 protected javax.swing.JButton stopButton;
 protected RenderCanvasFocusListener renderCanvasFocusListener = new RenderCanvasFocusListener();
 protected boolean shiftIsDown = false;

 protected javax.swing.JScrollPane textScrollPane;
 protected edu.cmu.cs.stage3.alice.authoringtool.util.StyledStreamTextPane detailTextPane = new edu.cmu.cs.stage3.alice.authoringtool.util.StyledStreamTextPane();

 protected boolean doNotListenToResize = false;
 protected final int dividerSize = 5; // the height to the bar serparating ? from output screen - 8
 protected String title;

 protected java.awt.event.ActionListener okActionListener;

 protected class TextOutputDocumentListener implements javax.swing.event.DocumentListener {
  public void insertUpdate (final javax.swing.event.DocumentEvent ev) {
   javax.swing.SwingUtilities.invokeLater( new Runnable() {
    public void run () {
     try {
      String textUpdate = ev.getDocument().getText(ev.getOffset(), ev.getLength());
      detailTextPane.getDocument().insertString(detailTextPane.getDocument().getLength(), textUpdate, detailTextPane.stdOutStyle);
     } catch (Exception e) {}
     update();
     }
    } );
   }

  public void removeUpdate( javax.swing.event.DocumentEvent ev) { update(); }
  public void changedUpdate( javax.swing.event.DocumentEvent ev) { update(); }

  private void update () {
   // System.out.println("RenderContentPane.java: update()");
   if (!(RenderContentPane.this.showStdOut)) {
    RenderContentPane.this.saveRenderBounds();
    javax.swing.SwingUtilities.invokeLater( new Runnable() {
     public void run () {
      RenderContentPane.this.updateGUI();
      RenderContentPane.this.showStdOut = true;
      java.awt.Component renderCanvas = getRenderCanvas();
      // String str = renderCanvas!=null ? "renderCanvas!=null":"renderCanvas==null";
      // System.out.println(" -- RenderContentPane.java: update: "+str);
      if (renderCanvas != null) {
       renderCanvas.requestFocus();
       }
      }
     } );
    }
   }
  }

 protected class RenderComponentListener extends java.awt.event.ComponentAdapter {
  //Rem @Override
  public void componentResized (java.awt.event.ComponentEvent ev) {
   if (RenderContentPane.this.shouldConstrainAspectOnResize() && !doNotListenToResize) {
    packDialog();
    doNotListenToResize = false;
    }
   }
  }

 protected TextOutputDocumentListener textListener = new TextOutputDocumentListener();
 protected RenderComponentListener renderResizeListener = new RenderComponentListener();

 public RenderContentPane (AuthoringTool authoringTool) {
  this.authoringTool = authoringTool;
  this.stdOutOutputComponent = AuthoringTool.getInstance().getStdOutOutputComponent();
  this.watcherPanel = authoringTool.getWatcherPanel();
  guiInit();
  }

 public void setAspectRatio (double aspectRatio) {
  this.aspectRatio = aspectRatio;
  }

 //Rem @Override
 public String getTitle () {
  return title;
  }

 public void setTitle (String newTitle) {
  title = newTitle;
  }

 protected void setRenderWindowSizeBasedOnSavedBounds () {
  renderPanel.setPreferredSize(new java.awt.Dimension(HEIGHT, 10)); // (new java.awt.Dimension(500, 10));
  }

 //Rem @Override
 public void preDialogShow (javax.swing.JDialog parentDialog) {
  // System.out.println("RenderContentPane.java: preDialogShow(...)");
  super.preDialogShow(parentDialog);
  final java.awt.Component renderCanvas = getRenderCanvas();
  if (renderCanvas != null) {
   renderCanvas.addFocusListener( renderCanvasFocusListener );
   javax.swing.Timer focusTimer = new javax.swing.Timer( 100, new java.awt.event.ActionListener() {
    public void actionPerformed (java.awt.event.ActionEvent ev) {
     // System.out.println("\n\n\nRenderContentPane.java: preDialogShow: renderCanvas.requestFocus");
     renderCanvas.requestFocus();
     }
    } );
   focusTimer.setRepeats( false );
   focusTimer.start();
   }
  stdOutOutputComponent.stdOutStream.println("*****"+I18n.getString("ivprogRun")+"*****"); // iVprog: running...
  stdOutOutputComponent.stdOutStream.flush();
  this.stdOutOutputComponent.getTextPane().getDocument().addDocumentListener(textListener);
  renderPanel.setPreferredSize(new java.awt.Dimension(500, 10));
  parentDialog.setLocation(170, 170);
  showStdOut = false;
  keyMapInit();
  updateGUI();
  }

 //Rem @Override
 public void postDialogShow (javax.swing.JDialog parentDialog) {
  super.postDialogShow(parentDialog);
  authoringTool.worldStopRunning();
  saveRenderBounds();
  showStdOut = false;
  java.awt.Component renderCanvas = getRenderCanvas();
  if (renderCanvas != null) {
   renderCanvas.removeFocusListener( renderCanvasFocusListener );
   }
  this.stdOutOutputComponent.getTextPane().getDocument().removeDocumentListener(textListener);
  stdOutOutputComponent.stdOutStream.println("*****"+I18n.getString("ivprogStop")+"*****"); // iVprog: stooped!
  stdOutOutputComponent.stdOutStream.flush();

  }

 //Rem @Override
 public void addOKActionListener (java.awt.event.ActionListener l) {
  okActionListener = l;
  stopButton.addActionListener(l);
  }

 //Rem @Override
 public void removeOKActionListener (java.awt.event.ActionListener l) {
  okActionListener = null;
  stopButton.removeActionListener(l);
  }


 // Draw the simulation panel
 private void guiInit () {
  // System.out.println("RenderContentPane.java: guiInit()");
  title = I18n.getString("ivprogRun"); // "iVprog: running..."
  // on renderPanel resize, constrain to aspectRatio
  setRenderWindowSizeBasedOnSavedBounds();
  renderPanel.addComponentListener( renderResizeListener );
  watcherScrollPane = new javax.swing.JScrollPane( watcherPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED );
  textScrollPane = new javax.swing.JScrollPane( detailTextPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED );
  detailTextPane.setEditable( false );

  // buttons
  pauseButton = new javax.swing.JButton( authoringTool.getActions().pauseWorldAction );
  resumeButton = new javax.swing.JButton( authoringTool.getActions().resumeWorldAction );
  restartButton = new javax.swing.JButton( authoringTool.getActions().restartWorldAction );
  stopButton = new javax.swing.JButton( authoringTool.getActions().stopWorldAction);

  pauseButton.setMargin(new java.awt.Insets(3,2,3,2));
  resumeButton.setMargin(new java.awt.Insets(3,2,3,2));
  restartButton.setMargin(new java.awt.Insets(3,2,3,2));
  stopButton.setMargin(new java.awt.Insets(3,2,3,2));

  buttonPanel.add( pauseButton, new java.awt.GridBagConstraints( 2, 0, 1, 2, 0.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 2, 2, 2, 2 ), 0, 0 ) );

  buttonPanel.add( resumeButton, new java.awt.GridBagConstraints( 5, 0, 1, 2, 0.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 2, 2, 2, 2 ), 0, 0 ) );
  buttonPanel.add( restartButton, new java.awt.GridBagConstraints( 6, 0, 1, 2, 0.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 2, 2, 2, 2 ), 0, 0 ) );
  buttonPanel.add( stopButton, new java.awt.GridBagConstraints( 7, 0, 1, 2, 0.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 2, 2, 2, 2 ), 0, 0 ) );

  watcherSplitPane = new javax.swing.JSplitPane( javax.swing.JSplitPane.HORIZONTAL_SPLIT );
  watcherSplitPane.setContinuousLayout( true );
  watcherSplitPane.setDividerSize( 0 );
  watcherSplitPane.setResizeWeight( 1.0 );
  watcherSplitPane.setLeftComponent(renderPanel);

  stdOutSplitPane = new javax.swing.JSplitPane( javax.swing.JSplitPane.VERTICAL_SPLIT );
  stdOutSplitPane.setContinuousLayout( true );
  stdOutSplitPane.setDividerSize( 0 );
  stdOutSplitPane.setResizeWeight( 1.0 );
  stdOutSplitPane.setTopComponent(watcherSplitPane);

  setLayout( new java.awt.BorderLayout() );
  add( buttonPanel, java.awt.BorderLayout.NORTH );
  add( stdOutSplitPane, java.awt.BorderLayout.CENTER );

  updateGUI();

  }

 private void keyMapInit () {
  javax.swing.KeyStroke keyStroke;
  String commandKey;
  for (java.util.Iterator iter = authoringTool.getActions().renderActions.iterator(); iter.hasNext();) {
   javax.swing.Action action = (javax.swing.Action)iter.next();
   try {
    keyStroke = (javax.swing.KeyStroke)action.getValue( javax.swing.Action.ACCELERATOR_KEY );
    commandKey = (String)action.getValue( javax.swing.Action.ACTION_COMMAND_KEY );
   } catch( ClassCastException e) {
    continue;
    }
   if ((keyStroke != null) && (commandKey != null)) {
    java.awt.Component root = javax.swing.SwingUtilities.getRoot( this );
    if (root instanceof javax.swing.JDialog) {
     ((javax.swing.JDialog)root).getRootPane().registerKeyboardAction( action, commandKey, keyStroke, javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW );
     } 
    }
   }
  }

 public void saveRenderBounds () {
  java.awt.Point pos = new java.awt.Point( 0, 0 );
  java.awt.Component root = javax.swing.SwingUtilities.getRoot( this );
  if (root instanceof javax.swing.JDialog) {
   javax.swing.SwingUtilities.convertPointToScreen( pos, root );
   } 
  else {
   javax.swing.SwingUtilities.convertPointToScreen( pos, renderPanel );
   }
  }

 public void saveRenderBounds (java.awt.Rectangle newBounds) { }

 protected boolean shouldConstrainAspectOnResize () {
  return !(showStdOut || authoringTool.getWatcherPanel().isThereSomethingToWatch());
  }

 public javax.swing.JPanel getRenderPanel () {
  System.out.println("RenderContentPane.java: getRenderPanel()");
  return renderPanel;
  }

 public void constrainToAspectRatio (java.awt.Rectangle bounds, boolean stretchHorizontally) {
  if (aspectRatio > 0.0) {
   if (stretchHorizontally) {
    bounds.width = (int)Math.round( bounds.height*aspectRatio );
   } else {
    bounds.height = (int)Math.round( bounds.width/aspectRatio );
    }
   }
  }

 public void stopWorld () {
  if (okActionListener != null) {
   okActionListener.actionPerformed(null);
   }
  }

 // At every start to simulate the programm
 public void updateGUI () {
  // System.out.println("RenderContentPane.java: updateGUI(): "+authoringTool.getWatcherPanel().isThereSomethingToWatch());

  int renderWidth = renderPanel.getWidth();
  int renderHeight = renderPanel.getHeight();

  // this looks much more complicated than it really is, although some of the code is quite tempermental
  if (showStdOut) { 
   textScrollPane.setPreferredSize(new java.awt.Dimension(renderWidth, stdOutHeight));
   stdOutSplitPane.setBottomComponent( textScrollPane );
   stdOutSplitPane.setDividerSize(dividerSize);
  } else {
   stdOutSplitPane.setBottomComponent(null);
   stdOutSplitPane.setDividerLocation(0);
   stdOutSplitPane.setDividerSize(0);
   }
  // Is there some variable with "watching" activated?
  if (authoringTool.getWatcherPanel().isThereSomethingToWatch()) { // AuthoringTool.java: edu.cmu.cs.stage3.alice.authoringtool.util.WatcherPanel watcherPanel
   watcherScrollPane.setPreferredSize(new java.awt.Dimension(watcherWidth, renderHeight));
   watcherSplitPane.setRightComponent( watcherScrollPane );
   watcherSplitPane.setDividerSize(dividerSize);
  } else {
   watcherSplitPane.setRightComponent( null );
   watcherSplitPane.setDividerLocation(0);
   watcherSplitPane.setDividerSize(0);
   }
  packDialog();
  }

 //Rem @Override
 public void addNotify () {
  super.addNotify();
  showStdOut = false;
  updateGUI();
  }

 public java.awt.Component getRenderCanvas () {
  java.awt.Component authoringToolRenderPanel = renderPanel.getComponent( 0 );
  if (authoringToolRenderPanel instanceof java.awt.Container) {
   try {
    return ((java.awt.Container)authoringToolRenderPanel).getComponent( 0 );
   } catch (Exception e) {
    //continue
    }
   }

  return null;
  }

 public class RenderCanvasFocusListener extends java.awt.event.FocusAdapter {
  public void focusLost () {
   java.awt.Component renderCanvas = getRenderCanvas();
   if ((renderCanvas != null) && renderCanvas.isShowing()) {
    System.out.println("\n\n\nRenderContentPane.java: focusLost: renderCanvas.requestFocus");
    //System.out.println("\n\n\nRenderContentPane.java: setRenderWindowSizeBasedOnSavedBounds: "+stdOutSplitPane.getHeight());
    //System.out.println("\n\n\nRenderContentPane.java: constrainToAspectRatio: "+stdOutSplitPane.getHeight()+": bounds.height="+bounds.height);
    renderCanvas.requestFocus();
    }
   }
  }

 }
